Add support for wrapping cargo's rustc invocations by setting RUSTC_WRAPPER
authorTed Mielczarek <ted@mielczarek.org>
Fri, 31 Mar 2017 16:39:19 +0000 (12:39 -0400)
committerTed Mielczarek <ted@mielczarek.org>
Tue, 18 Apr 2017 12:12:04 +0000 (08:12 -0400)
src/cargo/util/config.rs
src/cargo/util/rustc.rs
src/doc/environment-variables.md
tests/build.rs
tests/cargotest/lib.rs

index 17e909b97a2fe8e4667b4c2b53fa1bf1e109b0fe..762bc79de757ec70cdb6bd5b1f4f05ac5e4b0601 100644 (file)
@@ -93,7 +93,8 @@ impl Config {
     }
 
     pub fn rustc(&self) -> CargoResult<&Rustc> {
-        self.rustc.get_or_try_init(|| Rustc::new(self.get_tool("rustc")?))
+        self.rustc.get_or_try_init(|| Rustc::new(self.get_tool("rustc")?,
+                                                 self.maybe_get_tool("rustc_wrapper")?))
     }
 
     pub fn cargo_exe(&self) -> CargoResult<&Path> {
@@ -415,18 +416,27 @@ impl Config {
         }
     }
 
-    fn get_tool(&self, tool: &str) -> CargoResult<PathBuf> {
+    /// Look for a path for `tool` in an environment variable or config path, but return `None`
+    /// if it's not present.
+    fn maybe_get_tool(&self, tool: &str) -> CargoResult<Option<PathBuf>> {
         let var = tool.chars().flat_map(|c| c.to_uppercase()).collect::<String>();
         if let Some(tool_path) = env::var_os(&var) {
-            return Ok(PathBuf::from(tool_path));
+            return Ok(Some(PathBuf::from(tool_path)));
         }
 
         let var = format!("build.{}", tool);
         if let Some(tool_path) = self.get_path(&var)? {
-            return Ok(tool_path.val);
+            return Ok(Some(tool_path.val));
         }
 
-        Ok(PathBuf::from(tool))
+        Ok(None)
+    }
+
+    /// Look for a path for `tool` in an environment variable or config path, defaulting to `tool`
+    /// as a path.
+    fn get_tool(&self, tool: &str) -> CargoResult<PathBuf> {
+        self.maybe_get_tool(tool)
+            .map(|t| t.unwrap_or(PathBuf::from(tool)))
     }
 }
 
index 5bf2e74f3e0a889093310d348278aa19a2542b75..d401452d712fee08f0da58cfd4600f3d9387569b 100644 (file)
@@ -4,6 +4,7 @@ use util::{self, CargoResult, internal, ChainError, ProcessBuilder};
 
 pub struct Rustc {
     pub path: PathBuf,
+    pub wrapper: Option<PathBuf>,
     pub verbose_version: String,
     pub host: String,
 }
@@ -14,12 +15,12 @@ impl Rustc {
     ///
     /// If successful this function returns a description of the compiler along
     /// with a list of its capabilities.
-    pub fn new(path: PathBuf) -> CargoResult<Rustc> {
+    pub fn new(path: PathBuf, wrapper: Option<PathBuf>) -> CargoResult<Rustc> {
         let mut cmd = util::process(&path);
         cmd.arg("-vV");
-        
+
         let output = cmd.exec_with_output()?;
-        
+
         let verbose_version = String::from_utf8(output.stdout).map_err(|_| {
             internal("rustc -v didn't return utf8 output")
         })?;
@@ -36,12 +37,21 @@ impl Rustc {
 
         Ok(Rustc {
             path: path,
+            wrapper: wrapper,
             verbose_version: verbose_version,
             host: host,
         })
     }
 
     pub fn process(&self) -> ProcessBuilder {
-        util::process(&self.path)
+        if let Some(ref wrapper) = self.wrapper {
+            let mut cmd = util::process(wrapper);
+            {
+                cmd.arg(&self.path);
+            }
+            cmd
+        } else {
+            util::process(&self.path)
+        }
     }
 }
index 97bdb38cb51640a4166c1006773eb8b6a221edfd..77bfa71052e47cf8b2ddce9f66710f0ae4d57775 100644 (file)
@@ -17,6 +17,9 @@ system:
   relative to the current working directory.
 * `RUSTC` - Instead of running `rustc`, Cargo will execute this specified
   compiler instead.
+* `RUSTC_WRAPPER` - Instead of simply running `rustc`, Cargo will execute this
+  specified wrapper instead, passing as its commandline arguments the rustc
+  invocation, with the first argument being rustc.
 * `RUSTDOC` - Instead of running `rustdoc`, Cargo will execute this specified
   `rustdoc` instance instead.
 * `RUSTFLAGS` - A space-separated list of custom flags to pass to all compiler
index fa92dadffa7f713c73a933149567f024c9a8b39d..62018406f757592794b8508e6110246d757b14cc 100644 (file)
@@ -2899,3 +2899,18 @@ fn run_proper_binary_main_rs_as_foo() {
     assert_that(p.cargo_process("run").arg("--bin").arg("foo"),
                 execs().with_status(0));
 }
+
+#[test]
+fn rustc_wrapper() {
+    // We don't have /usr/bin/env on Windows.
+    if cfg!(windows) { return }
+
+    let p = project("foo")
+        .file("Cargo.toml", &basic_bin_manifest("foo"))
+        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));
+
+    assert_that(p.cargo_process("build").arg("-v").env("RUSTC_WRAPPER", "/usr/bin/env"),
+                execs().with_stderr_contains(
+                    "[RUNNING] `/usr/bin/env rustc --crate-name foo [..]")
+                .with_status(0));
+}
index a4410a85361fd6a39874e3fa2c7d65a2e770845b..15dc956cae84a6f6064c71a8b5f13f1d3c77b396 100644 (file)
@@ -27,7 +27,7 @@ use std::env;
 pub mod support;
 pub mod install;
 
-thread_local!(pub static RUSTC: Rustc = Rustc::new(PathBuf::from("rustc")).unwrap());
+thread_local!(pub static RUSTC: Rustc = Rustc::new(PathBuf::from("rustc"), None).unwrap());
 
 pub fn rustc_host() -> String {
     RUSTC.with(|r| r.host.clone())
@@ -54,6 +54,7 @@ fn _process(t: &OsStr) -> cargo::util::ProcessBuilder {
      .env_remove("__CARGO_DEFAULT_LIB_METADATA")
      .env_remove("RUSTC")
      .env_remove("RUSTDOC")
+     .env_remove("RUSTC_WRAPPER")
      .env_remove("RUSTFLAGS")
      .env_remove("CARGO_INCREMENTAL")
      .env_remove("XDG_CONFIG_HOME")      // see #2345